#include <QCoreApplication>
#include <QDebug>
#include "Dbkit.h"
#include "c_wrapper.h"
#include "Database/Database.h"
#include <QSqlRecord>
#include <QSqlError>
#include <QSqlField>
#include <iostream>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
#include <map>
#include <vector>
#include <variant>
//#include <Eigen/Sparse>

using namespace std;

#define q qDebug()
#define t(x) qDebug()<<#x":"<<(x)
//#define c(x) cout<<#x": "<<(x)

void testDbkitInterface() {
    q<<dbkit_new();
    q<<dbkit_execute("open: test");
    q<<dbkit_disconnect();
    q<<dbkit_connect("test");
    q<<dbkit_execute("");
    q<<dbkit_execute("#blahblahblah");
    q<<dbkit_execute("key: id");
    q<<dbkit_setMode("train");
    q<<dbkit_disconnect();
}

//void testDatabaseMysql() {
//    DatabaseMysql databaseMysql;
//    QVector<QVariantList> rows;
//    t(databaseMysql.connect("test"));
//    t(databaseMysql.setKey("id"));
//    t(databaseMysql.dropTable("src"));
//    t(databaseMysql.dropTable("dst"));
//    t(databaseMysql.createTable("src"));
//    t(databaseMysql.addColumn("src","val","VARCHAR(45)"));
//    t(databaseMysql.createTable("dst"));
//    t(databaseMysql.addColumn("dst","val","VARCHAR(45)"));
//    QStringList values;

//    for(int i=1; i<=3; i++) {
//        values.append(QString("%1").arg(i));
//    }
//    t(databaseMysql.addIds("src",values));
//    for(int i=0; i<3; i++)
//        t(databaseMysql.updateRowValue("src", "val", values[i],values[i]));

//    values.clear();

//    for(int i=3; i<=5; i++) {
//        values.append(QString("%1").arg(i));
//    }
//    t(databaseMysql.addIds("dst",values));
////    for(int i=0; i<3; i++) {
////        t(databaseMysql.addRowValue("dst", "val", values[i],values[i]));
////    }

//    t(databaseMysql.copy("dst","src"));
//    rows.clear();
//    t(databaseMysql.getRows(rows,"dst"));
////    q<<rows;
//    t(databaseMysql.disconnect());
//}

//void testDatabaseMysqlUtility() {
//    DatabaseMysql databaseMysql;
//    QString target,type,arg,mode;
//    auto parse=
//    [&databaseMysql,&target,&type,&arg,&mode] (QString name) ->bool{
//        if(!databaseMysql.interpretName(target,type,arg,mode,name))
//            return false;
////        t(name);
//        t(target);
//        t(type);
//        t(arg);
//        t(mode);
//        return true;
//    };
//    t(parse("企业信用-信用危机（聚类：一般、较大、大、极大）_predict"));
//    t(parse("企业信用-信用水平（标准：信用水平）"));
//    t(parse("企业负面状态（待合并）"));
//    t(parse("企业负面状态"));
//    t(parse("非空字段数_predict"));
//}

//void testDatabaseMysqlCompany() {
//    DatabaseMysql databaseMysql;
//    t(databaseMysql.connect("company_mini"));
//    t(databaseMysql.setKey("企业名称"));
////    t(databaseMysql.execute("cluster: tmp,企业信用-信用危机（聚类：一般、较大、大、极大）"));
////    t(databaseMysql.execute("count: tmp1,企业信用-信用危机（聚类：一般、较大、大、极大）"));
//    t(databaseMysql.execute("rate: tmp2,企业风险-司法风险（权重：司法风险）"));
//    t(databaseMysql.disconnect());
//}

void testDatabaseSqliteTrain() {
//    DatabaseSqlite databaseSqlite;
//    t(databaseSqlite.connect("company"));
//    t(databaseSqlite.execute("key:        企业名称"));

//    t(databaseSqlite.execute("cluster:    企业信用-信用水平（权重：信用水平）, 抽查通过率等级（聚类：F、E、D、C、B、A）"));
//    t(databaseSqlite.execute("cluster:    企业稳定性-稳定水平（权重：稳定水平）, 波动等级（聚类：A1、B1、C1、D1、E1、F1）"));
//    t(databaseSqlite.execute("cluster:    企业稳定性-稳定水平（权重：稳定水平）, 波动等级（聚类：A2、B2、C2、D2、E2、F2）"));
//    t(databaseSqlite.execute("cluster:    企业稳定性-稳定水平（权重：稳定水平）, 波动等级（聚类：A3、B3、C3、D3、E3、F3）"));
//    t(databaseSqlite.execute("cluster:    企业稳定性-稳定水平（权重：稳定水平）, 经营年限（聚类：E、D、C、B、A）"));
//    t(databaseSqlite.execute("cluster:    企业稳定性-稳定水平（权重：稳定水平）, 参保等级（聚类：C、B、A）"));
//    t(databaseSqlite.execute("cluster:    企业风险-司法风险（权重：司法风险）, 执行标的等级（聚类：E、D、C、B、A）"));
//    t(databaseSqlite.execute("cluster:    企业风险-司法风险（权重：司法风险）, 吊销等级（聚类：A2、B2、C2、D2、E2、F2）"));
//    t(databaseSqlite.execute("cluster:    企业风险-司法风险（权重：司法风险）, 吊销等级（聚类：A3、B3、C3、D3、E3、F3）"));
//    t(databaseSqlite.execute("copy:       聚类结果, 企业类型门类（待合并）"));
//    t(databaseSqlite.execute("copy:       聚类结果, 企业负面状态（待合并）"));
//    t(databaseSqlite.execute("copy:       聚类结果, 企业商标等级（待合并）"));
//    t(databaseSqlite.execute("copy:       聚类结果, 企业技术水平（待合并）"));
//    t(databaseSqlite.execute("eval:       评估"));
//    t(databaseSqlite.execute("rate:       企业信用-信用水平（聚类：较差、一般、较高、高）, 企业信用-信用水平（权重：信用水平）"));
//    t(databaseSqlite.execute("cluster:    聚类结果, 企业信用-信用水平（聚类：较差、一般、较高、高）"));
//    t(databaseSqlite.execute("count:      非空字段数, 企业信用-信用水平（聚类：较差、一般、较高、高）"));
//    t(databaseSqlite.execute("cluster:    聚类结果, 企业信用-信用危机（聚类：一般、较大、大、极大）, 企业信用-信用危机（影响）"));
//    t(databaseSqlite.execute("count:      非空字段数, 企业信用-信用危机（聚类：一般、较大、大、极大）"));
//    t(databaseSqlite.execute("cluster:    聚类结果, 企业稳定性-企业能力（聚类：差、较差、中等、较强、极强）, 企业稳定性-企业能力（影响）"));
//    t(databaseSqlite.execute("count:      非空字段数, 企业稳定性-企业能力（聚类：差、较差、中等、较强、极强）"));
//    t(databaseSqlite.execute("rate:       企业稳定性-稳定水平（聚类：高、较高、一般、较低、低）, 企业稳定性-稳定水平（权重：稳定水平）"));
//    t(databaseSqlite.execute("cluster:    聚类结果, 企业稳定性-稳定水平（聚类：高、较高、一般、较低、低）"));
//    t(databaseSqlite.execute("count:      非空字段数, 企业稳定性-稳定水平（聚类：高、较高、一般、较低、低）"));
//    t(databaseSqlite.execute("cluster:    聚类结果, 企业规模背景-企业年龄（聚类：中等、较长、长、极长）"));
//    t(databaseSqlite.execute("count:      非空字段数, 企业规模背景-企业年龄（聚类：中等、较长、长、极长）"));
//    t(databaseSqlite.execute("cluster:    聚类结果, 企业规模背景-企业规模（聚类：微小、较小、小、中等、较大）, 企业规模背景-企业规模（影响）"));
//    t(databaseSqlite.execute("count:      非空字段数, 企业规模背景-企业规模（聚类：微小、较小、小、中等、较大）"));
//    t(databaseSqlite.execute("rate:       企业风险-司法风险（聚类：一般、较大、大、极大）, 企业风险-司法风险（权重：司法风险）"));
//    t(databaseSqlite.execute("cluster:    聚类结果, 企业风险-司法风险（聚类：一般、较大、大、极大）, 企业风险-司法风险（影响）"));
//    t(databaseSqlite.execute("count:      非空字段数, 企业风险-司法风险（聚类：一般、较大、大、极大）"));
//    t(databaseSqlite.execute("cluster:    聚类结果, 企业风险-经营风险（聚类：一般、较大、大、极大）, 企业风险-经营风险（影响）"));
//    t(databaseSqlite.execute("count:      非空字段数, 企业风险-经营风险（聚类：一般、较大、大、极大）"));

//    t(databaseSqlite.disconnect());
}

void testDatabaseSqlite() {
//    DatabaseSqlite databaseSqlite;
//    t(databaseSqlite.connect("company"));

//    std::vector< std::vector<int> > rows;
//    t(databaseSqlite.getRows(rows,"企业风险-司法风险（影响）"));
//    t(rows[0].size());
//    for(auto row:rows) for(size_t i=0; i<row.size(); i++)
//            cout<<row[i]<<(i==row.size()-1?'\n':' ');

////    std::vector<std::string> ids;
////    databaseSqlite.setKey("字段名");
////    t(databaseSqlite.getIds(ids,"企业风险-司法风险（影响）"));
////    for(auto id:ids) cout<<id<<endl;

//    t(databaseSqlite.disconnect());
}

//void testDatabaseFly() {
//    DatabaseFly databaseFly;
//    databaseFly.connect("company.db");
//    databaseFly.disconnect();
//}

void testMemoryUsage() {
    t(sizeof(QVariant));
    t(sizeof(int));
    t(sizeof(double));
    t(sizeof(long long));
}

void testQSqlDatabase() {
    QSqlDatabase database;
    database.open();
    QSqlRecord record=database.record("企业信用-信用危机（聚类：一般、较大、大、极大）");
    t(record);
    t(record.field(0).type());
    database.close();
}

void testDriverSqlite() {
    DriverSqlite driver;
    driver.setDatabase("company.db");
//    Table table("企业信用-信用危机（影响）");
//    table.addColumn(Column("字段名"));
//    table.addColumn(Column("影响力",Column::Real));
//    driver.loadTable(table);
//    table.name="企业信用-信用危机（影响）_2";
//    driver.saveTable(table);
//    driver.loadTable(table);
//    t(driver.connection.record(table.name));
    Database database;
    driver.loadStructure(database);
    driver.loadDatabase(database);
    puts("Loaded");
    database.name="company_2.db";
//    driver.saveDatabase(database);
    driver.connection.setDatabaseName("company_2.db");
    driver.saveTable(database.getTable("聚类结果"));
    puts("Saved");
    puts("press enter to exit");
    getchar();
}

void testDbkit() {
    puts("Dbkit");
    Dbkit dbkit;
    t(dbkit.connect("company.db"));
    t(dbkit.execute("key: 企业名称"));
    t(dbkit.setCheckpoint("company.checkpoint"));
    t(dbkit.executeScript("company.script"));
    t(dbkit.rename("我的聚类结果","聚类结果"));
    t(dbkit.save({"我的聚类结果"}));
    t(dbkit.disconnect());
}

void testCWrapper() {
    t(dbkit_new());
    t(dbkit_connect("company.db"));
    t(dbkit_execute("key: 企业名称"));
    t(dbkit_setCheckpoint("company.checkpoint"));
    t(dbkit_executeScript("company.script"));
    t(dbkit->rename("我的聚类结果2","聚类结果"));
    t(dbkit->save({"我的聚类结果2"}));
    t(dbkit_disconnect());
    t(dbkit_delete());
}

void testCWrapperJson() {
    t(dbkit_new());
    t(dbkit_connect("test.db"));
    t(dbkit_execute("load: 账户,个人信息"));
    QString code;
    QJsonObject data;
    QString input,output;

    // Insert
    code="0";
    data=QJsonObject();
    data["table"]="账户";
    data["columns"]=QJsonArray{"用户名","密码","管理员"};
    data["rows"]=QJsonArray{
        QJsonArray{"user1","password1",false},
        QJsonArray{"user2","password2",true}
    };
    t(data);
    dbkit->json_pack(input,code,data);
    t(dbkit->json_insertRows(output,input));
    dbkit->json_unpack(code,data,output);
    t(code);
    t(data);

    // Update
    code="0";
    data=QJsonObject();
    data["table"]="账户";
    data["columns"]=QJsonArray{"用户名","密码"};
    data["rows"]=QJsonArray{
        QJsonArray{"user1","newPassword"}
    };
    t(data);
    dbkit->json_pack(input,code,data);
    t(dbkit->json_updateRows(output,input));
    dbkit->json_unpack(code,data,output);
    t(code);
    t(data);

    // Select
    code="0";
    data=QJsonObject();
    data["table"]="账户";
    data["columns"]=QJsonArray{"用户名","密码","管理员"};
    data["ids"]=QJsonArray();
    data["constraints"]=QJsonArray();
    data["orderby"]=QJsonArray();
    data["limit"]=30;
    data["page"]=1;
    t(data);
    dbkit->json_pack(input,code,data);
    t(dbkit->json_selectRows(output,input));
    dbkit->json_unpack(code,data,output);
    t(code);
    t(data);

    // Select entire row
    code="0";
    data=QJsonObject();
    data["tables"]=QJsonArray{"账户","个人信息"};
    data["columns"]=QJsonArray{
        QJsonArray{"用户名","管理员"},
        QJsonArray{"昵称","性别"}
    };
    data["id"]="guest";
    t(data);
    dbkit->json_pack(input,code,data);
    t(dbkit->json_selectJoinedRow(output,input));
    dbkit->json_unpack(code,data,output);
    t(code);
    t(data);

    // Delete
    code="0";
    data=QJsonObject();
    data["table"]="账户";
    data["ids"]=QJsonArray{"user1","user2"};
    t(data);
    dbkit->json_pack(input,code,data);
    t(dbkit->json_deleteRows(output,input));
    dbkit->json_unpack(code,data,output);
    t(code);
    t(data);


    t(dbkit->save({"账户"}));
    t(dbkit_delete());
}

void testCWrapperDbkitJson() {
    dbkit_new();
    t(dbkit_connect("test.db"));
    t(dbkit_execute("load"));
    const char *input=
//        R"({"code":"0","data":{"table":"个人信息","column":"性别"}})";
        R"({"code":"0","data":{"table":"账户","column":"管理员"}})";
    char *output;
    t(dbkit_json_sum(input,&output));
    t(output);
    dbkit_delete();
}

void testShadow() {
    dbkit_new();
    dbkit_connect("test.db");
    t(dbkit->load({"账户"}));
    t(dbkit->clone("Cloned","账户"));
    t(dbkit->save({"Cloned"}));
    dbkit_delete();
}

void testPredict() {
    dbkit_new();
    t(dbkit_connect("company.db"));

    t(dbkit_executeScript("takeOff.script"));

    t(dbkit_setMode("train"));
    t(dbkit_setCheckpoint("company.checkpoint"));
    t(dbkit_executeScript("train.script"));

    t(dbkit_setMode("predict"));
    t(dbkit_setCheckpoint("company.checkpoint"));
    t(dbkit_executeScript("createTemp.script"));
    t(dbkit_executeScript("predict.script"));
    t(dbkit_executeScript("dropTemp.script"));

    t(dbkit_executeScript("land.script"));

    dbkit_delete();
}

void testMemory() {
    Dbkit dbkit;
    dbkit.connect("test.db");
    dbkit.execute("load: Whole");
    puts("loaded");
    getchar();
}

void testMemoryMap() {
    QSqlDatabase db=QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName("test.db");
    vector<map<int,QVariant>> t;
    map<QString,int> iColumn;
    map<QString,int> iRow;
    db.open();
    QSqlQuery query=db.exec("select * from Whole;");
    int nColumn=query.record().count();
    for(int i=0; i<nColumn; i++) {
        QString columnName=query.record().fieldName(i);
        iColumn.insert(make_pair(columnName,i));
    }
    vector<vector<bool>> isNull(nColumn);
    while(query.next()) {
        map<int,QVariant> r;
        for(int i=0; i<nColumn; i++) {
            isNull[i].push_back(query.value(i).isNull());
            if(!isNull[i].back())
                r.insert(make_pair(i,query.value(i)));
        }
        t.push_back(move(r));
    }
    db.close();
    puts("loaded");
    getchar();
}

ostream &operator<<(ostream &out, QVariant &c1) {  //进来后又出去
    out<<c1.toString().toStdString();
    return out;
}

//void testMemoryEigen() {
//    QSqlDatabase db=QSqlDatabase::addDatabase("QSQLITE");
//    db.setDatabaseName("test.db");
//    db.open();
//    QSqlQuery query=db.exec("select count(*) from Whole;");
//    query.next();
//    int nRow=query.value(0).toInt();
//    map<QString,int> iColumn;
//    map<QString,int> iRow;
//    query=db.exec("select * from Whole;");
//    int nColumn=query.record().count();
//    Eigen::SparseMatrix<QVariant *> table(nRow,nColumn);
//    for(int i=0; i<nColumn; i++) {
//        QString columnName=query.record().fieldName(i);
//        iColumn.insert(make_pair(columnName,i));
//    }
//    vector<vector<bool>> isNull(nColumn);
//    int i=0,j;
//    while(query.next()) {
//        for(j=0; j<nColumn; j++) {
//            isNull[j].push_back(query.value(j).isNull());
//            if(!isNull[j].back())
//                table.insert(i,j)=new QVariant(query.value(j));
//        }
//        i++;
//    }
//    table.makeCompressed();
//    db.close();
//    puts("loaded");
//    getchar();
//}

//void testEigen() {
//    int nRow=2,nCol=3;
//    Eigen::SparseMatrix<QVariant *> m(nRow,nCol);
//    m.insert(0,1)=new QVariant(4);
//    q<<m.coeff(1,2);
//    q<<*(m.coeff(0,1));
//}


int main(int argc, char* argv[]) {
    QCoreApplication app(argc,argv);
//    testMemory();
//    testMemoryMap();
//    t(sizeof(int));
//    t(sizeof(long long));
//    t(sizeof(double));
//    t(sizeof(string));
//    t(sizeof(QVariant));
//    t(sizeof(QString));
//    t(sizeof(vector<int>));
//    t(sizeof(QVector<int>));

    t(dbkit_new());
	t(dbkit_connect("company.db"));
//    t(dbkit->execute("load"));
//	t(dbkit->setKey("企业名称"));
	QString mode="train";
	t(dbkit_setMode(mode.toUtf8().data()));
	t(dbkit_setCheckpoint("company.checkpoint"));
	t(dbkit_executeScript(QString("scripts/"+mode+".script").toUtf8().data()));
//	t(dbkit->save({"聚类结果_predict"}));
	t(dbkit_disconnect());
	t(dbkit_delete());
    return 0;
}
